#include "countdown.h"
using namespace std;
CountDown::CountDown(QWidget *parent) : PreventCloseWindow(parent)
{
	setAttribute(Qt::WA_TransparentForMouseEvents, true);
	setAttribute(Qt::WA_TranslucentBackground);
	setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::ToolTip | Qt::WindowDoesNotAcceptFocus);
	setFocusPolicy(Qt::NoFocus);
	setWindowOpacity(0.95);
	setGeometry(g_availableGeometry);
	timestr->setAlignment(Qt::AlignCenter);
	timestr->setFont(QFont(MAINFT, 27));
	if (liveMode) timestr->setStyleSheet("background-color: transparent; color: #ffff00;");
	else timestr->setStyleSheet("border-radius: 15px;background-color: #000000; color: #ffffff;");
	ganfan->setStyleSheet("color: #ff0000;");
	ganfan->setFont(QFont(MAINFT, 80, QFont::Bold));
	danmuLabel->setStyleSheet("color:#808080; font-size: 35px; font-weight: bold;");
	danmuLabel->setAlignment(Qt::AlignCenter);
	danmuLabel->setText("欢迎使用教室多媒体系统,系统正在初始化⌛ 作者 linux-rm; 主程序版本 " PROJECT_VERSION);
	danmuLabel->adjustSize();
	danmuLabel->move(0, 0);
	connect(timer3, &QTimer::timeout, this, &CountDown::GanFanUpdata);
	connect(masterTimer, &QTimer::timeout, this, &CountDown::timerUpdata);
	connect(mouseTimer, &QTimer::timeout, this, &CountDown::updateMouseTransparency);
	connect(danmuTimer, &QTimer::timeout, this, &CountDown::spawnBarrage);
	timer3->start(1000);
	masterTimer->start(32);
	mouseTimer->start(1000);
	danmuTimer->start(5000);
	timerUpdata();
	GanFanUpdata();
	holidays.clear();
	QFile file(noticeFilePath);
	if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
		QTextStream in(&file);
		while (!in.atEnd()) {
			QString line = in.readLine().trimmed();
			if (!line.isEmpty()) holidays.append(line);
		}
		file.close();
	}
	subjects.clear();
	QDir dir(subjectsDirPath);
	if (dir.exists()) {
		QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
		foreach (const QString &file, files) {
			QFile subjectFile(dir.filePath(file));
			if (subjectFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
				QTextStream in(&subjectFile);
				while (!in.atEnd()) {
					QString line = in.readLine().trimmed();
					if (!line.isEmpty()) subjects.append(line);
				}
				subjectFile.close();
			}
		}
	}
	timestr->move((screenw - timestr->geometry().width()) / 2, timestrY);
	ganfan->setGeometry(0, 0, screenw, screenh);
}
CountDown::~CountDown() {}
#define FILL0(X) setw(X) << std::setfill('0')
void CountDown::timerUpdata()
{
	QDateTime current = QDateTime::currentDateTime();
	QTime currentTime = current.time();
	currentTimestamp = static_cast<long double>(current.toMSecsSinceEpoch()) / 1000.0;
	int second = current.time().second();
	if (current.time().msec() > 500) colon = ':';
	else colon = ' ';
	QDate date = current.date();
	int year = date.year();
	int month = date.month();
	int day = date.day();
	int dayOfWeek = date.dayOfWeek() - 1;
	if (Config::instance().hiddenSubjects().contains(g_currentClassInfo.subject) && g_currentClassInfo.isInClass) {
		timestr->hide();
		return;
	} else timestr->show();
	double remainingSecondsToGaokao = Config::instance().gaokaoTimestamp() - currentTimestamp;
	double remainingHours = remainingSecondsToGaokao / 3600.0;
	double remainingDays = remainingSecondsToGaokao / 86400.0;
	int daysRemaining = static_cast<int>(remainingDays);
	int hoursRemaining = static_cast<int>(remainingHours);
	string days_fractionalStr = QString("%1").arg(static_cast<int>(fabs(remainingDays - daysRemaining) * 1.0e6 + 0.5), 6, 10, QChar('0')).toStdString();
	string hours_fractionalStr = QString("%1").arg(static_cast<int>(fabs(remainingHours - hoursRemaining) * 1.0e4 + 0.4), 4, 10, QChar('0')).toStdString();
	std::stringstream tmp;
	if (liveMode) timestr->setStyleSheet(daysRemaining <= 30 ? "background-color: rgba(255,0,0,0.5); color: #000000;" : daysRemaining <= 100 ? "background-color: transparent; color: #ff0000;" : "background-color: transparent; color: #ffff00;");
	else timestr->setStyleSheet(daysRemaining <= 30 ? "border-radius: 15px;background-color: #ff0000; color: #000000;" : daysRemaining <= 100 ? "border-radius: 15px;background-color: #000000; color: #ff0000;" : "border-radius: 15px;background-color: #000000; color: #ffffff;");
	if (isFullScreenMode || isDesktopActive()) {
		tmp << "<b>距离高考还有<br /><span style='";
		if (isFullScreenMode) tmp << "font-size:300pt;";
		tmp << "color:" << (daysRemaining <= 100 ? "#ffffff" : "#ff0000") << ";'>" << daysRemaining << "</span>." << days_fractionalStr << "天<br />相当于<span style=\"color:" << (daysRemaining <= 100 ? "#ffffff" : "#ff0000") << ";\">" << hoursRemaining << "</span>." << hours_fractionalStr << "小时</b><br />" << year << '-' << month << '-' << day << week[dayOfWeek] << FILL0(2) << current.time().hour() << colon << FILL0(2) << current.time().minute() << colon << FILL0(2) << second;
		if (liveMode) tmp << "<br />上一届:" << daysRemaining - 365 << "天 下一届:" << daysRemaining + 365 << "天";
		timestr->setText(QString::fromStdString(tmp.str()));
	} else {
		if ((second % 10 == 3)) tmp << year << '-' << month << '-' << day << week[dayOfWeek];
		else if ((second % 10 < 5)) tmp << "还有<b style=\"color:" << (daysRemaining <= 100 ? "#ffffff" : "#ff0000") << ";\">" << daysRemaining << "</b>." << days_fractionalStr << "天";
		else tmp << "高考<b style=\"color:" << (daysRemaining <= 100 ? "#ffffff" : "#ff0000") << ";\">" << hoursRemaining << "</b>." << hours_fractionalStr << "小时";
		tmp << ' ' << FILL0(2) << current.time().hour() << colon << FILL0(2) << current.time().minute() << colon << FILL0(2) << second;
		timestr->setText(QString::fromStdString(tmp.str()));
	}
	if (!isChanging && !isFullScreenMode) timestr->adjustSize();
	if (g_currentClassInfo.isInClass) {
		double totalSeconds = g_currentClassInfo.startTime.secsTo(g_currentClassInfo.endTime);
		if (totalSeconds > 0) {
			g_currentClassInfo.progress = qBound(0.0, static_cast<double>(g_currentClassInfo.startTime.secsTo(currentTime) + current.time().msec() / 1000.0) / totalSeconds, 1.0);
			timestr->setBorderColor(QColor(0, 128, 255));
			timestr->setProgress(g_currentClassInfo.progress);
		}
	} else {
		timestr->setBorderColor(daysRemaining <= 30 ? QColor(255, 255, 0) : daysRemaining <= 200 ? QColor(192, 0, 0) : QColor(0, 0, 255));
		timestr->setProgress((currentTimestamp - Config::instance().enrollmentTimestamp()) / (double) (Config::instance().gaokaoTimestamp() - Config::instance().enrollmentTimestamp()));
	}
}
void CountDown::updateMouseTransparency()
{
#ifdef Q_OS_WIN
	SetWindowPos(reinterpret_cast<HWND>(winId()), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
#endif
#ifdef Q_OS_WIN
	bool isScreenSaverEnabled = liveMode;
	if (Config::instance().screensaver() && !liveMode) {
		LASTINPUTINFO lii = {sizeof(LASTINPUTINFO)};
		if (GetLastInputInfo(&lii)) {
			DWORD idleTime = GetTickCount() - lii.dwTime;
			isScreenSaverEnabled = (idleTime >= 9e5 || (!g_currentClassInfo.isInClass && idleTime >= 3e5)) && !isAudioPlaying();
		}
	}
#else
	bool isScreenSaverEnabled = Config::instance().screensaver() || liveMode;
#endif
	if (isScreenSaverEnabled) {
		if (!isFullScreenMode) {
			isFullScreenMode = 1;
			setWindowOpacity(0.95);
			timestr->setWordWrap(true);
			timestr->setBorderWidth(50);
			timestr->setFont(QFont(MAINFT, 27, QFont::Normal));
			ganfan->setFont(QFont(MAINFT, 200, QFont::Bold));
			QPropertyAnimation *animation1 = new QPropertyAnimation(timestr, "geometry");
			animation1->setDuration(600);
			animation1->setStartValue(timestr->geometry());
			animation1->setEndValue(QRect(0, 0, screenw, screenh));
			animation1->setEasingCurve(QEasingCurve::InQuad);
			animation1->start();
		}
		return;
	}
	if (isFullScreenMode) {
		ganfan->setFont(QFont(MAINFT, 80, QFont::Bold));
		ganfan->setGeometry(0, 0, screenw, screenh);
		timestr->setBorderWidth(10);
		timestr->setWordWrap(false);
		isPositionChanged = !isPositionChanged;
		trans();
	}
	if (timestr->y() != timestrY && !isPositionChanged) timestr->setGeometry(timestr->x(), timestrY, timestr->width(), timestr->height());
	isFullScreenMode = 0;
	if (isFullScreenMode || isChanging) return;
	m_point = QCursor::pos();
	if ((m_point.x() == cursorPosX) || (m_point.y() == cursorPosY)) setWindowOpacity(0.95);
	else if (!isChanging) setWindowOpacity(0.3);
	cursorPosX = m_point.x() - screenx;
	cursorPosY = m_point.y() - screeny;
	if ((m_point.y() < screeny + 300) && !isPositionChanged) {
		isPositionChanged = 1;
		trans();
		return;
	} else if ((m_point.y() > screeny + screenh - 250) && isPositionChanged) {
		isPositionChanged = 0;
		trans();
		return;
	}
	if (timestr->x() + timestr->width() > screenw) timestr->move(screenw - timestr->width(), timestr->y());
	if (timestr->y() + timestr->height() > screenh) timestr->move(timestr->x(), screenh - timestr->height());
}
void CountDown::GanFanUpdata()
{
	QDateTime current = QDateTime::currentDateTime();
	QTime time = current.time();
	int second = time.second();
	int msec = time.msec();
	int currentMinutes = time.hour() * 60 + time.minute();
	double totalSeconds = 60.0 - (second + msec / 1000.0);
	int int_sec = static_cast<int>(totalSeconds);
	int fractional = static_cast<int>((totalSeconds - int_sec) * 100);
	std::stringstream GanFan;
	QStringList ganfanList = Config::instance().ganfanTimes();
	QStringList shutdownList = Config::instance().shutdownTimes();
	if (ganfanList.contains(QString::number(currentMinutes))) {
		GanFan << "干饭" << int_sec << '.' << FILL0(2) << fractional << "s";
		ganfan->setBorderColor(QColor(0, 255, 0));
		ganfan->setProgress((second + msec / 1000.0) / 60.0);
		setWindowOpacity(1);
		if (isFullScreenProgressActive) {
			isFullScreenProgressActive = 0;
			timer3->stop();
			timer3->start(1);
			ganfan->show();
		}
	} else if (shutdownList.contains(QString::number(currentMinutes))) {
		if (second > 55) system("shutdown -s -f -t 0");
		GanFan << "关机" << int_sec << '.' << FILL0(2) << fractional << "s";
		ganfan->setBorderColor(QColor(0, 255, 255));
		ganfan->setProgress((second + msec / 1000.0) / 60.0);
		setWindowOpacity(1);
		if (isFullScreenProgressActive) {
			isFullScreenProgressActive = 0;
			timer3->stop();
			timer3->start(1);
			ganfan->show();
		}
	} else {
		isFullScreenProgressActive = 1;
		timer3->stop();
		timer3->start(1000);
		ganfan->hide();
	}
	ganfan->setGeometry(0, 0, screenw, screenh);
	ganfan->setText(QString::fromStdString(GanFan.str()));
	timerUpdata();
}
void CountDown::trans()
{
	if (isChanging) return;
	isChanging = true;
	setWindowOpacity(0.95);
	QPropertyAnimation *animation3 = new QPropertyAnimation(timestr, "geometry");
	animation3->setDuration(300);
	animation3->setStartValue(timestr->geometry());
	animation3->setEndValue(isPositionChanged ? QRect(timestr->x(), -timestr->height(), timestr->width(), timestr->height()) : QRect(timestr->x(), screenh, timestr->width(), timestr->height()));
	animation3->setEasingCurve(QEasingCurve::InQuad);
	animation3->start();
	QTimer::singleShot(300, this, [=]() {
		timestr->adjustSize();
		setWindowOpacity(0.95);
		int ax = screenx + (screenw - timestr->width()) * (1.0 - static_cast<double>(cursorPosX - screenx) / screenw);
		if (!isPositionChanged) timestr->move(ax, -timestr->geometry().height());
		else timestr->move(ax, screenh);
		QPropertyAnimation *animation2 = new QPropertyAnimation(timestr, "geometry");
		animation2->setDuration(600);
		animation2->setStartValue(timestr->geometry());
		if (!isPositionChanged) animation2->setEndValue(QRect(ax, timestrY, timestr->width(), timestr->geometry().height()));
		else animation2->setEndValue(QRect(ax, screenh - timestr->geometry().height(), timestr->width(), timestr->geometry().height()));
		animation2->setEasingCurve(QEasingCurve::OutQuad);
		animation2->start();
		QTimer::singleShot(600, this, [=]() { isChanging = false; });
	});
}
void CountDown::spawnBarrage()
{
	if ((!Config::instance().barrage()) || (!liveMode && (g_currentClassInfo.isInClass || isAudioPlaying()))) {
		timestrY = 0;
		if (danmuLabel) danmuLabel->hide();
		isDanmuAnimating = false;
		return;
	}
	if (isDanmuAnimating) return;
	QString text;
	if (barrageCounter == 0) {
		QList<QPair<QDateTime, QString>> validHolidays;
		QDateTime now = QDateTime::currentDateTime();
		QFile file(noticeFilePath);
		if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
			QTextStream in(&file);
			while (!in.atEnd()) {
				QString line = in.readLine().trimmed();
				if (line.length() < 19) continue;
				bool isStarred = line.contains('*');
				QDateTime holidayTime = QDateTime::fromString(line.left(19), "yyyy-MM-dd HH:mm:ss");
				if (!holidayTime.isValid()) continue;
				qint64 secsTo = now.secsTo(holidayTime);
				if (secsTo < -86400) continue;
				QString holidayName = line.mid(20).trimmed();
				QString displayText;
				if (secsTo >= 86400) displayText = QString("%1天后%2").arg(secsTo / 86400.0, 0, 'f', 2).arg(holidayName);
				else if (secsTo >= 0) displayText = QString("%1小时%2分钟后%3").arg(secsTo / 3600).arg((secsTo % 3600) / 60).arg(holidayName);
				else displayText = "现在: " + holidayName;
				if (isStarred) displayText = "**" + displayText + "**";
				validHolidays.append(qMakePair(holidayTime, displayText));
			}
			file.close();
		}
		QStringList holidayStrings;
		for (int i = 0; i < qMin(5, validHolidays.size()); ++i) holidayStrings.append(validHolidays[i].second);
		text = holidayStrings.join(" | ");
		if (text.isEmpty()) text = "无节日";
	} else {
		QDir dir(subjectsDirPath);
		QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
		if (!files.isEmpty()) {
			int fileIndex = QRandomGenerator::global()->bounded(files.size());
			QString filePath = dir.filePath(files[fileIndex]);
			QFile file(filePath);
			if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
				QTextStream in(&file);
				QStringList lines;
				while (!in.atEnd()) {
					QString line = in.readLine().trimmed();
					if (!line.isEmpty()) lines.append(line);
				}
				if (!lines.isEmpty()) {
					int lineIndex = QRandomGenerator::global()->bounded(lines.size());
					text = lines[lineIndex];
				}
			}
			file.close();
		}
		if (text.isEmpty()) text = "无学科知识点";
	}
	if (barrageCounter > 5) barrageCounter = 0;
	else barrageCounter++;
	danmuLabel->setText(text);
	danmuLabel->adjustSize();
	int contentWidth = danmuLabel->width();
	int contentHeight = danmuLabel->height();
	timestrY = contentHeight;
	if (contentWidth < screenw) {
		danmuLabel->setGeometry((screenw - contentWidth) / 2, 0, contentWidth, contentHeight);
		danmuLabel->show();
		QTimer::singleShot(10000, this, [this]() {
			danmuLabel->hide();
			isDanmuAnimating = false;
			spawnBarrage();
		});
	} else {
		danmuLabel->setGeometry(screenw, 0, contentWidth, contentHeight);
		danmuLabel->show();
		QPropertyAnimation *danmuAnimation = new QPropertyAnimation(danmuLabel, "geometry");
		danmuAnimation->setDuration((contentWidth + screenw) * 10);
		danmuAnimation->setStartValue(QRect(screenw, 0, contentWidth, contentHeight));
		danmuAnimation->setEndValue(QRect(-contentWidth, 0, contentWidth, contentHeight));
		danmuAnimation->setEasingCurve(QEasingCurve::Linear);
		connect(danmuAnimation, &QPropertyAnimation::finished, this, [this]() {
			danmuLabel->hide();
			isDanmuAnimating = false;
			spawnBarrage();
		});
		danmuAnimation->start();
	}
	isDanmuAnimating = true;
}
